package com.fly.show.controller;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.NotBlank;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import com.fly.core.annotation.ResourceLimit;
import com.fly.core.annotation.Status;
import com.fly.core.interceptor.AnnotationHelper;
import com.fly.core.log.annotation.Log;
import com.fly.core.log.enums.BusinessType;
import com.fly.core.utils.ShellExecutor;
import com.fly.show.model.JsonResult;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.annotations.ApiOperation;
import lombok.Data;
import lombok.experimental.Accessors;

/**
 * 
 * IndexController
 * 
 * @author 00fly
 * @version [版本号, 2020-04-16]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
@Api(tags = "首页接口")
@Controller
@ConditionalOnWebApplication
public class IndexController
{
    @Autowired
    ApplicationContext applicationContext;
    
    @Autowired
    RequestMappingHandlerMapping mapping;
    
    @Autowired
    HttpServletRequest request;
    
    /**
     * 首页
     * 
     * @param model
     * @return
     * @throws Exception
     * @see [类、类#方法、类#成员]
     */
    @Log(title = "首页访问", businessType = BusinessType.OTHER)
    @GetMapping("/index")
    public String index(Model model)
        throws Exception
    {
        // 输出docker应用映射端口
        String dockerCmd = "docker ps --format \"{{.Names}} {{.Ports}}\"";
        Map<String, Set<String>> map = new TreeMap<>();
        ShellExecutor.exec(dockerCmd)
            .stream()
            .map(line -> Collections.singletonMap(StringUtils.substringBefore(line, " "),
                Stream.of(StringUtils.substringAfter(line, " ").split(",")).map(p -> StringUtils.substringBetween(p, ":", "->")).filter(StringUtils::isNotBlank).map(p -> p.replace(":", "")).sorted().collect(Collectors.toSet())))
            .forEach(it -> map.putAll(it));
        
        // controller->url
        List<URLInfo> urlList = getAllURLInfo().stream().filter(url -> url.getClassName().startsWith("com.fly") && "GET".equals(url.getType())).collect(Collectors.toList());
        Map<String, Set<String>> urlMap = new TreeMap<>();
        urlList.forEach(u -> {
            String className = u.getClassName();
            if (!urlMap.containsKey(className))
            {
                urlMap.put(className, new TreeSet<String>());
            }
            urlMap.get(className).addAll(u.getUrl());
        });
        
        model.addAttribute("baseUrl", StringUtils.substringBeforeLast(request.getRequestURL().toString(), ":"));
        model.addAttribute("urls", AnnotationHelper.getRequestMappingURL(applicationContext));
        model.addAttribute("urlMap", urlMap);
        model.addAttribute("map", map);
        return "/index";
    }
    
    private List<URLInfo> getAllURLInfo()
    {
        List<URLInfo> urlList = new ArrayList<>();
        Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();
        for (Map.Entry<RequestMappingInfo, HandlerMethod> m : map.entrySet())
        {
            URLInfo urlInfo = new URLInfo();
            RequestMappingInfo info = m.getKey();
            for (String url : info.getPatternsCondition().getPatterns())
            {
                urlInfo.getUrl().add(url);
            }
            HandlerMethod method = m.getValue();
            urlInfo.setClassName(method.getMethod().getDeclaringClass().getName()).setMethod(method.getMethod().getName());
            String type = info.getMethodsCondition().toString();
            if (type != null && type.startsWith("[") && type.endsWith("]"))
            {
                urlInfo.setType(type.substring(1, type.length() - 1));
            }
            urlList.add(urlInfo);
        }
        return urlList;
    }
    
    /**
     * 登录, 10分钟内，失败次数超3次，20分钟后再试
     * 
     * @param input
     * @return
     * @see [类、类#方法、类#成员]
     */
    @ApiOperation("用户登录")
    @PostMapping("/login")
    @ResourceLimit(circle = 10, condition = Status.FAILURE, maxCount = 3, next = 20)
    public @ResponseBody JsonResult<?> login(@Validated DataInput input)
    {
        if ("00fly".equals(input.getUserName()) && "password".equals(input.getPassWord()))
        {
            return JsonResult.success("登录成功");
        }
        return JsonResult.error("登录失败");
    }
    
    @Data
    class DataInput
    {
        @NotBlank(message = "用户名不能为空")
        @ApiModelProperty(value = "用户名", example = "00fly", required = true)
        private String userName;
        
        @NotBlank(message = "密码不能为空")
        @ApiModelProperty(value = "密码", example = "password", required = true)
        private String passWord;
    }
    
    @Data
    @Accessors(chain = true)
    class URLInfo
    {
        private List<String> url = new ArrayList<>();
        
        private String method;
        
        private String type;
        
        private String className;
    }
}
